Interactive graphics with plotly
install.packages("plotly")
First Interactive Plot
library(tidyverse)
library(plotly)
p <- ggplot(data = midwest) +
geom_point(mapping = aes(x = popdensity, y = percollege))
ggplotly(p)
Customized Interactive Plot
p <- ggplot(midwest,
aes(x = popdensity, y = percollege, color = state)) +
geom_point() +
scale_x_continuous("Population Density",
breaks = seq(0, 80000, 20000)) +
scale_y_continuous("Percent College Graduates") +
scale_color_discrete("State") +
theme_bw()
ggplotly(p)
Your Turn
- Using the
starwars data, create a static ggplot and use the ggplotly function to turn it interactive.
Lord of the Rings Data
lotr <- read_tsv('https://raw.githubusercontent.com/jennybc/lotr/master/lotr_clean.tsv')
lotr
Create plotly by hand
plot_ly(lotr, x = ~Words) %>% add_histogram()
Subplots
one_plot <- function(d) {
plot_ly(d, x = ~Words) %>%
add_histogram() %>%
add_annotations(
~unique(Film), x = 0.5, y = 1,
xref = "paper", yref = "paper", showarrow = FALSE
)
}
lotr %>%
split(.$Film) %>%
lapply(one_plot) %>%
subplot(nrows = 1, shareX = TRUE, titleX = FALSE) %>%
hide_legend()
Grouped bar plot
plot_ly(lotr, x = ~Race, color = ~Film) %>% add_histogram()
Plot of proportions
## number of diamonds by cut and clarity (n)
lotr_count <- count(lotr, Race, Film)
## number of diamonds by cut (nn)
lotr_prop <- left_join(lotr_count, count(lotr_count, Race, wt = n),
by = 'Race')
lotr_prop %>%
mutate(prop = n.x / n.y) %>%
plot_ly(x = ~Race, y = ~prop, color = ~Film, width = 900) %>%
add_bars() %>%
layout(barmode = "stack")
Your Turn
- Using the
gss_cat data, create a histrogram for the tvhours variable.
- Using the
gss_cat data, create a bar chart showing the partyid variable by the marital status.
Scatterplots by Hand
plot_ly(midwest, x = ~popdensity, y = ~percollege) %>%
add_markers()
Change symbol
plot_ly(midwest, x = ~popdensity, y = ~percollege) %>%
add_markers(symbol = ~state)
Change color
plot_ly(midwest, x = ~popdensity, y = ~percollege) %>%
add_markers(color = ~state, colors = viridis::viridis(5))
Line Graph
storms_yearly <- storms %>%
group_by(year) %>%
summarise(num = length(unique(name)))
plot_ly(storms_yearly, x = ~year, y = ~num) %>%
add_lines()
Your Turn
- Using the
gss_cat data, create a scatterplot showing the age and tvhours variables.
- Compute the average time spent watching tv by year and marital status. Then, plot the average time spent watching tv by year and marital status.
Highcharter; Highcharts for R
devtools::install_github("jbkunst/highcharter")
hchart function
library(highcharter)
Highcharts (www.highcharts.com) is a Highsoft software product which is
not free for commercial and Governmental use
lotr_count <- lotr %>%
count(Film, Race)
hchart(lotr_count, "column", hcaes(x = Race, y = n, group = Film))
A second hchart
hchart(midwest, "scatter", hcaes(x = popdensity, y = percollege, group = state))
Histogram
hchart(lotr$Words)
Your Turn
- Using the
hchart function, create a bar chart or histogram with the gss_cat data.
- Using the
hchart function, create a scatterplot with the gss_cat data.
Build Highcharts from scratch
hc <- highchart() %>%
hc_xAxis(categories = lotr_count$Race) %>%
hc_add_series(name = 'The Fellowship Of The Ring',
data = filter(lotr_count, Film == 'The Fellowship Of The Ring')$n) %>%
hc_add_series(name = 'The Two Towers',
data = filter(lotr_count, Film == 'The Two Towers')$n) %>%
hc_add_series(name = 'The Return Of The King',
data = filter(lotr_count, Film == 'The Return Of The King')$n)
hc
Change Chart type
hc <- hc %>%
hc_chart(type = 'column')
hc
Change Colors
hc <- hc %>%
hc_colors(substr(viridis::viridis(3), 0, 7))
hc
Modify Axes
hc <- hc %>%
hc_xAxis(title = list(text = "Race")) %>%
hc_yAxis(title = list(text = "Number of Words Spoken"),
showLastLabel = FALSE)
hc
Add title, subtitle, move legend
hc <- hc %>%
hc_title(text = 'Number of Words Spoken in Lord of the Rings Films',
align = 'left') %>%
hc_subtitle(text = 'Broken down by <i>Film</i> and <b>Race</b>',
align = 'left') %>%
hc_legend(align = 'right', verticalAlign = 'top', layout = 'vertical',
x = 0, y = 80) %>%
hc_exporting(enabled = TRUE)
hc
Your Turn
- Build up a plot from scratch, getting the figure close to publication quality using the
gss_cat data.
Correlation Matrices
select(storms, wind, pressure, ts_diameter, hu_diameter) %>%
cor(use = "pairwise.complete.obs") %>%
hchart()
Leaflet Example
library(leaflet)
storms %>%
filter(name %in% c('Ike', 'Katrina'), year > 2000) %>%
leaflet() %>%
addTiles() %>%
addCircles(lng = ~long, lat = ~lat, popup = ~name, weight = 1,
radius = ~wind*1000)
LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIC0gSW50ZXJhY3RpdmUgR3JhcGhpY3MgdXNpbmcgUiIKYXV0aG9yOiAiQnJhbmRvbiBMZUJlYXUiCmRhdGU6ICJGZWJydWFyeSAyMSwgMjAxOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXBfY2h1bmtzLCBlY2hvID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NiwgZmlnLmNhcCA9IE5VTEwpIApgYGAKCiMgSW50ZXJhY3RpdmUgZ3JhcGhpY3Mgd2l0aCBwbG90bHkKYGBge3IgaW5zdGFsbCwgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQpgYGAKCiMgRmlyc3QgSW50ZXJhY3RpdmUgUGxvdApgYGB7ciBmaXJzdF9wbG90bHksIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKcCA8LSBnZ3Bsb3QoZGF0YSA9IG1pZHdlc3QpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHBvcGRlbnNpdHksIHkgPSBwZXJjb2xsZWdlKSkKZ2dwbG90bHkocCkKYGBgCgojIEN1c3RvbWl6ZWQgSW50ZXJhY3RpdmUgUGxvdApgYGB7ciBjdXN0b21fcGxvdGx5LCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA2fQpwIDwtIGdncGxvdChtaWR3ZXN0LCAKICAgICAgIGFlcyh4ID0gcG9wZGVuc2l0eSwgeSA9IHBlcmNvbGxlZ2UsIGNvbG9yID0gc3RhdGUpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKCJQb3B1bGF0aW9uIERlbnNpdHkiLCAKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDgwMDAwLCAyMDAwMCkpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKCJQZXJjZW50IENvbGxlZ2UgR3JhZHVhdGVzIikgKyAKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZSgiU3RhdGUiKSArIAogIHRoZW1lX2J3KCkKZ2dwbG90bHkocCkKYGBgCgojIFlvdXIgVHVybgoxLiBVc2luZyB0aGUgYHN0YXJ3YXJzYCBkYXRhLCBjcmVhdGUgYSBzdGF0aWMgZ2dwbG90IGFuZCB1c2UgdGhlIGBnZ3Bsb3RseWAgZnVuY3Rpb24gdG8gdHVybiBpdCBpbnRlcmFjdGl2ZS4gCgojIExvcmQgb2YgdGhlIFJpbmdzIERhdGEKLSBEYXRhIGZyb20gSmVubnkgQnJ5YW46IDxodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9sb3RyPgoKYGBge3IgcmVhZF9pbl9sb3RyLCBlcnJvciA9IEZBTFNFfQpsb3RyIDwtIHJlYWRfdHN2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vamVubnliYy9sb3RyL21hc3Rlci9sb3RyX2NsZWFuLnRzdicpCmxvdHIKYGBgCgojIENyZWF0ZSBwbG90bHkgYnkgaGFuZApgYGB7ciBwbG90bHlfYnlfaGFuZCwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDZ9CnBsb3RfbHkobG90ciwgeCA9IH5Xb3JkcykgJT4lIGFkZF9oaXN0b2dyYW0oKQpgYGAKCiMgU3VicGxvdHMKYGBge3Igc3VicGxvdHMsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA2fQpvbmVfcGxvdCA8LSBmdW5jdGlvbihkKSB7CiAgcGxvdF9seShkLCB4ID0gfldvcmRzKSAlPiUKICAgIGFkZF9oaXN0b2dyYW0oKSAlPiUKICAgIGFkZF9hbm5vdGF0aW9ucygKICAgICAgfnVuaXF1ZShGaWxtKSwgeCA9IDAuNSwgeSA9IDEsIAogICAgICB4cmVmID0gInBhcGVyIiwgeXJlZiA9ICJwYXBlciIsIHNob3dhcnJvdyA9IEZBTFNFCiAgICApCn0KCmxvdHIgJT4lCiAgc3BsaXQoLiRGaWxtKSAlPiUKICBsYXBwbHkob25lX3Bsb3QpICU+JSAKICBzdWJwbG90KG5yb3dzID0gMSwgc2hhcmVYID0gVFJVRSwgdGl0bGVYID0gRkFMU0UpICU+JQogIGhpZGVfbGVnZW5kKCkKYGBgCgoKIyBHcm91cGVkIGJhciBwbG90CmBgYHtyIHBsb3RseV9ncm91cCwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDZ9CnBsb3RfbHkobG90ciwgeCA9IH5SYWNlLCBjb2xvciA9IH5GaWxtKSAlPiUgYWRkX2hpc3RvZ3JhbSgpCmBgYAoKIyBQbG90IG9mIHByb3BvcnRpb25zCmBgYHtyIHBsb3RseV9wcm9wb3J0aW9ucywgbWVzc2FnZSA9IEZBTFNFLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNn0KIyMgbnVtYmVyIG9mIGRpYW1vbmRzIGJ5IGN1dCBhbmQgY2xhcml0eSAobikKbG90cl9jb3VudCA8LSBjb3VudChsb3RyLCBSYWNlLCBGaWxtKQojIyBudW1iZXIgb2YgZGlhbW9uZHMgYnkgY3V0IChubikKbG90cl9wcm9wIDwtIGxlZnRfam9pbihsb3RyX2NvdW50LCBjb3VudChsb3RyX2NvdW50LCBSYWNlLCB3dCA9IG4pLCAKICAgICAgICAgICAgICAgICAgICAgICBieSA9ICdSYWNlJykKCmxvdHJfcHJvcCAlPiUKICBtdXRhdGUocHJvcCA9IG4ueCAvIG4ueSkgJT4lCiAgcGxvdF9seSh4ID0gflJhY2UsIHkgPSB+cHJvcCwgY29sb3IgPSB+RmlsbSwgd2lkdGggPSA5MDApICU+JQogIGFkZF9iYXJzKCkgJT4lCiAgbGF5b3V0KGJhcm1vZGUgPSAic3RhY2siKQpgYGAKCiMgWW91ciBUdXJuCjEuIFVzaW5nIHRoZSBgZ3NzX2NhdGAgZGF0YSwgY3JlYXRlIGEgaGlzdHJvZ3JhbSBmb3IgdGhlIGB0dmhvdXJzYCB2YXJpYWJsZS4gCjIuIFVzaW5nIHRoZSBgZ3NzX2NhdGAgZGF0YSwgY3JlYXRlIGEgYmFyIGNoYXJ0IHNob3dpbmcgdGhlIGBwYXJ0eWlkYCB2YXJpYWJsZSBieSB0aGUgYG1hcml0YWxgIHN0YXR1cy4KCiMgU2NhdHRlcnBsb3RzIGJ5IEhhbmQKYGBge3IgcGxvdGx5X3NjYXR0ZXIsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA2LCB3YXJuaW5nID0gRkFMU0V9CnBsb3RfbHkobWlkd2VzdCwgeCA9IH5wb3BkZW5zaXR5LCB5ID0gfnBlcmNvbGxlZ2UpICU+JQogIGFkZF9tYXJrZXJzKCkKYGBgCgojIENoYW5nZSBzeW1ib2wKYGBge3IgcGxvdGx5X3N5bWJvbCwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDZ9CnBsb3RfbHkobWlkd2VzdCwgeCA9IH5wb3BkZW5zaXR5LCB5ID0gfnBlcmNvbGxlZ2UpICU+JQogIGFkZF9tYXJrZXJzKHN5bWJvbCA9IH5zdGF0ZSkKYGBgCgojIENoYW5nZSBjb2xvcgpgYGB7ciBwbG90bHlfY29sb3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA5fQpwbG90X2x5KG1pZHdlc3QsIHggPSB+cG9wZGVuc2l0eSwgeSA9IH5wZXJjb2xsZWdlKSAlPiUKICBhZGRfbWFya2Vycyhjb2xvciA9IH5zdGF0ZSwgY29sb3JzID0gdmlyaWRpczo6dmlyaWRpcyg1KSkKYGBgCgojIExpbmUgR3JhcGgKYGBge3IgcGxvdGx5X2xpbmUsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA5fQpzdG9ybXNfeWVhcmx5IDwtIHN0b3JtcyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UobnVtID0gbGVuZ3RoKHVuaXF1ZShuYW1lKSkpCgpwbG90X2x5KHN0b3Jtc195ZWFybHksIHggPSB+eWVhciwgeSA9IH5udW0pICU+JQogIGFkZF9saW5lcygpCmBgYAoKIyBZb3VyIFR1cm4KMS4gVXNpbmcgdGhlIGBnc3NfY2F0YCBkYXRhLCBjcmVhdGUgYSBzY2F0dGVycGxvdCBzaG93aW5nIHRoZSBgYWdlYCBhbmQgYHR2aG91cnNgIHZhcmlhYmxlcy4KMi4gQ29tcHV0ZSB0aGUgYXZlcmFnZSB0aW1lIHNwZW50IHdhdGNoaW5nIHR2IGJ5IHllYXIgYW5kIG1hcml0YWwgc3RhdHVzLiBUaGVuLCBwbG90IHRoZSBhdmVyYWdlIHRpbWUgc3BlbnQgd2F0Y2hpbmcgdHYgYnkgeWVhciBhbmQgbWFyaXRhbCBzdGF0dXMuCgojIEhpZ2hjaGFydGVyOyBIaWdoY2hhcnRzIGZvciBSCmBgYHtyIGluc3RhbGxfaGlnaGNoYXJ0ZXIsIGV2YWwgPSBGQUxTRX0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJqYmt1bnN0L2hpZ2hjaGFydGVyIikKYGBgCgojIGBoY2hhcnRgIGZ1bmN0aW9uCmBgYHtyIGhjaGFydDEsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA5fQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQoKbG90cl9jb3VudCA8LSBsb3RyICU+JQogIGNvdW50KEZpbG0sIFJhY2UpCgpoY2hhcnQobG90cl9jb3VudCwgImNvbHVtbiIsIGhjYWVzKHggPSBSYWNlLCB5ID0gbiwgZ3JvdXAgPSBGaWxtKSkKYGBgCgojIEEgc2Vjb25kIGBoY2hhcnRgCmBgYHtyIGhjaGFydDIsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA5fQpoY2hhcnQobWlkd2VzdCwgInNjYXR0ZXIiLCBoY2Flcyh4ID0gcG9wZGVuc2l0eSwgeSA9IHBlcmNvbGxlZ2UsIGdyb3VwID0gc3RhdGUpKQpgYGAKCiMgSGlzdG9ncmFtCmBgYHtyIGhjaGFydF9oaXN0LCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOX0KaGNoYXJ0KGxvdHIkV29yZHMpCmBgYAoKIyBZb3VyIFR1cm4KMS4gVXNpbmcgdGhlIGBoY2hhcnRgIGZ1bmN0aW9uLCBjcmVhdGUgYSBiYXIgY2hhcnQgb3IgaGlzdG9ncmFtIHdpdGggdGhlIGBnc3NfY2F0YCBkYXRhLgoyLiBVc2luZyB0aGUgYGhjaGFydGAgZnVuY3Rpb24sIGNyZWF0ZSBhIHNjYXR0ZXJwbG90IHdpdGggdGhlIGBnc3NfY2F0YCBkYXRhLgoKIyBCdWlsZCBIaWdoY2hhcnRzIGZyb20gc2NyYXRjaApgYGB7ciBoY19zY3JhdGNoLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNn0KaGMgPC0gaGlnaGNoYXJ0KCkgJT4lCiAgaGNfeEF4aXMoY2F0ZWdvcmllcyA9IGxvdHJfY291bnQkUmFjZSkgJT4lCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gJ1RoZSBGZWxsb3dzaGlwIE9mIFRoZSBSaW5nJywgCiAgICAgICAgICAgICAgICBkYXRhID0gZmlsdGVyKGxvdHJfY291bnQsIEZpbG0gPT0gJ1RoZSBGZWxsb3dzaGlwIE9mIFRoZSBSaW5nJykkbikgJT4lIAogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICdUaGUgVHdvIFRvd2VycycsIAogICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihsb3RyX2NvdW50LCBGaWxtID09ICdUaGUgVHdvIFRvd2VycycpJG4pICU+JQogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICdUaGUgUmV0dXJuIE9mIFRoZSBLaW5nJywgCiAgICAgICAgICAgICAgICBkYXRhID0gZmlsdGVyKGxvdHJfY291bnQsIEZpbG0gPT0gJ1RoZSBSZXR1cm4gT2YgVGhlIEtpbmcnKSRuKQpoYwpgYGAKCiMgQ2hhbmdlIENoYXJ0IHR5cGUKYGBge3IgaGNfY2hhcnQsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA2fQpoYyA8LSBoYyAlPiUKICBoY19jaGFydCh0eXBlID0gJ2NvbHVtbicpCmhjCmBgYAoKIyBDaGFuZ2UgQ29sb3JzCmBgYHtyIGhjX2NoYW5nZV9jb2xvcnMsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA2fQpoYyA8LSBoYyAlPiUKICBoY19jb2xvcnMoc3Vic3RyKHZpcmlkaXM6OnZpcmlkaXMoMyksIDAsIDcpKQpoYwpgYGAKCiMgTW9kaWZ5IEF4ZXMKYGBge3IgaGNfYXhpcywgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDl9CmhjIDwtIGhjICU+JQogIGhjX3hBeGlzKHRpdGxlID0gbGlzdCh0ZXh0ID0gIlJhY2UiKSkgJT4lCiAgaGNfeUF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiTnVtYmVyIG9mIFdvcmRzIFNwb2tlbiIpLAogICAgICAgICAgIHNob3dMYXN0TGFiZWwgPSBGQUxTRSkKaGMKYGBgCgojIEFkZCB0aXRsZSwgc3VidGl0bGUsIG1vdmUgbGVnZW5kCmBgYHtyIGhjX21vZGlmeSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDl9CmhjIDwtIGhjICU+JQogIGhjX3RpdGxlKHRleHQgPSAnTnVtYmVyIG9mIFdvcmRzIFNwb2tlbiBpbiBMb3JkIG9mIHRoZSBSaW5ncyBGaWxtcycsCiAgICAgICAgICAgYWxpZ24gPSAnbGVmdCcpICU+JQogIGhjX3N1YnRpdGxlKHRleHQgPSAnQnJva2VuIGRvd24gYnkgPGk+RmlsbTwvaT4gYW5kIDxiPlJhY2U8L2I+JywgCiAgICAgICAgICAgICAgYWxpZ24gPSAnbGVmdCcpICU+JQogIGhjX2xlZ2VuZChhbGlnbiA9ICdyaWdodCcsIHZlcnRpY2FsQWxpZ24gPSAndG9wJywgbGF5b3V0ID0gJ3ZlcnRpY2FsJywKICAgICAgICAgICAgeCA9IDAsIHkgPSA4MCkgJT4lCiAgaGNfZXhwb3J0aW5nKGVuYWJsZWQgPSBUUlVFKQpoYwpgYGAKCgojIFlvdXIgVHVybgoxLiBCdWlsZCB1cCBhIHBsb3QgZnJvbSBzY3JhdGNoLCBnZXR0aW5nIHRoZSBmaWd1cmUgY2xvc2UgdG8gcHVibGljYXRpb24gcXVhbGl0eSB1c2luZyB0aGUgYGdzc19jYXRgIGRhdGEuCgojIENvcnJlbGF0aW9uIE1hdHJpY2VzCmBgYHtyIGNvcnJlbGF0aW9ufQpzZWxlY3Qoc3Rvcm1zLCB3aW5kLCBwcmVzc3VyZSwgdHNfZGlhbWV0ZXIsIGh1X2RpYW1ldGVyKSAlPiUKICBjb3IodXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpICU+JQogIGhjaGFydCgpCmBgYAoKIyBMZWFmbGV0IEV4YW1wbGUKYGBge3IgbGVhZmxldH0KbGlicmFyeShsZWFmbGV0KQoKc3Rvcm1zICU+JQogIGZpbHRlcihuYW1lICVpbiUgYygnSWtlJywgJ0thdHJpbmEnKSwgeWVhciA+IDIwMDApICU+JQogIGxlYWZsZXQoKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZXMobG5nID0gfmxvbmcsIGxhdCA9IH5sYXQsIHBvcHVwID0gfm5hbWUsIHdlaWdodCA9IDEsCiAgICAgICAgICAgICByYWRpdXMgPSB+d2luZCoxMDAwKQpgYGAKCgojIEFkZGl0aW9uYWwgUmVzb3VyY2VzCiogcGxvdGx5IGZvciBSIGJvb2s6IDxodHRwczovL3Bsb3RseS1ib29rLmNwc2lldmVydC5tZS8+CiogcGxvdGx5OiA8aHR0cHM6Ly9wbG90Lmx5Lz4KKiBoaWdoY2hhcnRlcjogPGh0dHA6Ly9qa3Vuc3QuY29tL2hpZ2hjaGFydGVyL2luZGV4Lmh0bWw+CiogaGlnaGNoYXJ0czogPGh0dHBzOi8vd3d3LmhpZ2hjaGFydHMuY29tLz4KKiBodG1sd2lkZ2V0czogPGh0dHBzOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy8+Cg==